home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / prog / dflt18.arj / TEXTBOX.C < prev    next >
Text File  |  1994-01-28  |  27KB  |  872 lines

  1. /* ------------- textbox.c ------------ */
  2.  
  3. #include "dflat.h"
  4.  
  5. static void ComputeWindowTop(WINDOW);
  6. static void ComputeWindowLeft(WINDOW);
  7. static int ComputeVScrollBox(WINDOW);
  8. static int ComputeHScrollBox(WINDOW);
  9. static void MoveScrollBox(WINDOW, int);
  10. static char *GetTextLine(WINDOW, int);
  11.  
  12. BOOL VSliding;
  13. BOOL HSliding;
  14.  
  15. /* ------------ ADDTEXT Message -------------- */
  16. static BOOL AddTextMsg(WINDOW wnd, char *txt)
  17. {
  18.     /* --- append text to the textbox's buffer --- */
  19.     unsigned adln = strlen(txt);
  20.     if (adln > (unsigned)0xfff0)
  21.         return FALSE;
  22.     if (wnd->text != NULL)    {
  23.         /* ---- appending to existing text ---- */
  24.         unsigned txln = strlen(wnd->text);
  25.         if ((long)txln+adln > (unsigned) 0xfff0)
  26.             return FALSE;
  27.         if (txln+adln > wnd->textlen)    {
  28.             wnd->text = DFrealloc(wnd->text, txln+adln+3);
  29.             wnd->textlen = txln+adln+1;
  30.         }
  31.     }
  32.     else    {
  33.         /* ------ 1st text appended ------ */
  34.         wnd->text = DFcalloc(1, adln+3);
  35.         wnd->textlen = adln+1;
  36.     }
  37.     if (wnd->text != NULL)    {
  38.         /* ---- append the text ---- */
  39.         strcat(wnd->text, txt);
  40.         strcat(wnd->text, "\n");
  41.         BuildTextPointers(wnd);
  42.         return TRUE;
  43.     }
  44.     return FALSE;
  45. }
  46.  
  47. /* ------------ DELETETEXT Message -------------- */
  48. static void DeleteTextMsg(WINDOW wnd, int lno)
  49. {
  50.     char *cp1 = TextLine(wnd, lno);
  51.     --wnd->wlines;
  52.     if (lno == wnd->wlines)
  53.         *cp1 = '\0';
  54.     else     {
  55.         char *cp2 = TextLine(wnd, lno+1);
  56.         memmove(cp1, cp2, strlen(cp2)+1);
  57.     }
  58.     BuildTextPointers(wnd);
  59. }
  60.  
  61. /* ------------ INSERTTEXT Message -------------- */
  62. static void InsertTextMsg(WINDOW wnd, char *txt, int lno)
  63. {
  64.     if (AddTextMsg(wnd, txt))    {
  65.         int len = strlen(txt);
  66.         char *cp2 = TextLine(wnd, lno);
  67.         char *cp1 = cp2+len+1;
  68.         memmove(cp1, cp2, strlen(cp2)-len);
  69.         strcpy(cp2, txt);
  70.         *(cp2+len) = '\n';
  71.         BuildTextPointers(wnd);
  72.     }
  73. }
  74.  
  75. /* ------------ SETTEXT Message -------------- */
  76. static void SetTextMsg(WINDOW wnd, char *txt)
  77. {
  78.     /* -- assign new text value to textbox buffer -- */
  79.     unsigned int len = strlen(txt)+1;
  80.     SendMessage(wnd, CLEARTEXT, 0, 0);
  81.     wnd->textlen = len;
  82.     wnd->text=DFrealloc(wnd->text, len+1);
  83.     wnd->text[len] = '\0';
  84.     strcpy(wnd->text, txt);
  85.     BuildTextPointers(wnd);
  86. }
  87.  
  88. /* ------------ CLEARTEXT Message -------------- */
  89. static void ClearTextMsg(WINDOW wnd)
  90. {
  91.     /* ----- clear text from textbox ----- */
  92.     if (wnd->text != NULL)
  93.         free(wnd->text);
  94.     wnd->text = NULL;
  95.     wnd->textlen = 0;
  96.     wnd->wlines = 0;
  97.     wnd->textwidth = 0;
  98.     wnd->wtop = wnd->wleft = 0;
  99.     ClearTextBlock(wnd);
  100.     ClearTextPointers(wnd);
  101. }
  102.  
  103. /* ------------ KEYBOARD Message -------------- */
  104. static int KeyboardMsg(WINDOW wnd, PARAM p1)
  105. {
  106.     switch ((int) p1)    {
  107.         case UP:
  108.             return SendMessage(wnd,SCROLL,FALSE,0);
  109.         case DN:
  110.             return SendMessage(wnd,SCROLL,TRUE,0);
  111.         case FWD:
  112.             return SendMessage(wnd,HORIZSCROLL,TRUE,0);
  113.         case BS:
  114.             return SendMessage(wnd,HORIZSCROLL,FALSE,0);
  115.         case PGUP:
  116.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  117.         case PGDN:
  118.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  119.         case CTRL_PGUP:
  120.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  121.         case CTRL_PGDN:
  122.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  123.         case HOME:
  124.             return SendMessage(wnd,SCROLLDOC,TRUE,0);
  125.         case END:
  126.             return SendMessage(wnd,SCROLLDOC,FALSE,0);
  127.         default:
  128.             break;
  129.     }
  130.     return FALSE;
  131. }
  132.  
  133. /* ------------ LEFT_BUTTON Message -------------- */
  134. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  135. {
  136.     int mx = (int) p1 - GetLeft(wnd);
  137.     int my = (int) p2 - GetTop(wnd);
  138.     if (TestAttribute(wnd, VSCROLLBAR) &&
  139.                         mx == WindowWidth(wnd)-1)    {
  140.         /* -------- in the right border ------- */
  141.         if (my == 0 || my == ClientHeight(wnd)+1)
  142.             /* --- above or below the scroll bar --- */
  143.             return FALSE;
  144.         if (my == 1)
  145.             /* -------- top scroll button --------- */
  146.             return SendMessage(wnd, SCROLL, FALSE, 0);
  147.         if (my == ClientHeight(wnd))
  148.             /* -------- bottom scroll button --------- */
  149.             return SendMessage(wnd, SCROLL, TRUE, 0);
  150.         /* ---------- in the scroll bar ----------- */
  151.         if (!VSliding && my-1 == wnd->VScrollBox)    {
  152.             RECT rc;
  153.             VSliding = TRUE;
  154.             rc.lf = rc.rt = GetRight(wnd);
  155.             rc.tp = GetTop(wnd)+2;
  156.             rc.bt = GetBottom(wnd)-2;
  157.             return SendMessage(NULL, MOUSE_TRAVEL,
  158.                 (PARAM) &rc, 0);
  159.         }
  160.         if (my-1 < wnd->VScrollBox)
  161.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  162.         if (my-1 > wnd->VScrollBox)
  163.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  164.     }
  165.     if (TestAttribute(wnd, HSCROLLBAR) &&
  166.                         my == WindowHeight(wnd)-1) {
  167.         /* -------- in the bottom border ------- */
  168.         if (mx == 0 || my == ClientWidth(wnd)+1)
  169.             /* ------  outside the scroll bar ---- */
  170.             return FALSE;
  171.         if (mx == 1)
  172.             return SendMessage(wnd, HORIZSCROLL,FALSE,0);
  173.         if (mx == WindowWidth(wnd)-2)
  174.             return SendMessage(wnd, HORIZSCROLL,TRUE,0);
  175.         if (!HSliding && mx-1 == wnd->HScrollBox)    {
  176.             /* --- hit the scroll box --- */
  177.             RECT rc;
  178.             rc.lf = GetLeft(wnd)+2;
  179.             rc.rt = GetRight(wnd)-2;
  180.             rc.tp = rc.bt = GetBottom(wnd);
  181.             /* - keep the mouse in the scroll bar - */
  182.             SendMessage(NULL,MOUSE_TRAVEL,(PARAM)&rc,0);
  183.             HSliding = TRUE;
  184.             return TRUE;
  185.         }
  186.         if (mx-1 < wnd->HScrollBox)
  187.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  188.         if (mx-1 > wnd->HScrollBox)
  189.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  190.     }
  191.     return FALSE;
  192. }
  193.  
  194. /* ------------ MOUSE_MOVED Message -------------- */
  195. static BOOL MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  196. {
  197.     int mx = (int) p1 - GetLeft(wnd);
  198.     int my = (int) p2 - GetTop(wnd);
  199.     if (VSliding)    {
  200.         /* ---- dragging the vertical scroll box --- */
  201.         if (my-1 != wnd->VScrollBox)    {
  202.             foreground = FrameForeground(wnd);
  203.             background = FrameBackground(wnd);
  204.             wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  205.                     wnd->VScrollBox+1);
  206.             wnd->VScrollBox = my-1;
  207.             wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  208.                     my);
  209.         }
  210.         return TRUE;
  211.     }
  212.     if (HSliding)    {
  213.         /* --- dragging the horizontal scroll box --- */
  214.         if (mx-1 != wnd->HScrollBox)    {
  215.             foreground = FrameForeground(wnd);
  216.             background = FrameBackground(wnd);
  217.             wputch(wnd, SCROLLBARCHAR, wnd->HScrollBox+1,
  218.                     WindowHeight(wnd)-1);
  219.             wnd->HScrollBox = mx-1;
  220.             wputch(wnd, SCROLLBOXCHAR, mx, WindowHeight(wnd)-1);
  221.         }
  222.         return TRUE;
  223.     }
  224.     return FALSE;
  225. }
  226.  
  227. /* ------------ BUTTON_RELEASED Message -------------- */
  228. static void ButtonReleasedMsg(WINDOW wnd)
  229. {
  230.     if (HSliding || VSliding)    {
  231.         /* release the mouse ouside the scroll bar */
  232.         SendMessage(NULL, MOUSE_TRAVEL, 0, 0);
  233.         VSliding ? ComputeWindowTop(wnd):ComputeWindowLeft(wnd);
  234.         SendMessage(wnd, PAINT, 0, 0);
  235.         SendMessage(wnd, KEYBOARD_CURSOR, 0, 0);
  236.         VSliding = HSliding = FALSE;
  237.     }
  238. }
  239.  
  240. /* ------------ SCROLL Message -------------- */
  241. static BOOL ScrollMsg(WINDOW wnd, PARAM p1)
  242. {
  243.     /* ---- vertical scroll one line ---- */
  244.     if (p1)    {
  245.         /* ----- scroll one line up ----- */
  246.         if (wnd->wtop+ClientHeight(wnd) >= wnd->wlines)
  247.             return FALSE;
  248.         wnd->wtop++;
  249.     }
  250.     else    {
  251.         /* ----- scroll one line down ----- */
  252.         if (wnd->wtop == 0)
  253.             return FALSE;
  254.         --wnd->wtop;
  255.     }
  256.     if (isVisible(wnd))    {
  257.         RECT rc;
  258.         rc = ClipRectangle(wnd, ClientRect(wnd));
  259.         if (ValidRect(rc))    {
  260.             /* ---- scroll the window ----- */
  261.             if (wnd != inFocus)
  262.                 SendMessage(wnd, PAINT, 0, 0);
  263.             else    {
  264.                 scroll_window(wnd, rc, (int)p1);
  265.                 if (!(int)p1)
  266.                     /* -- write top line (down) -- */
  267.                     WriteTextLine(wnd,NULL,wnd->wtop,FALSE);
  268.                 else    {
  269.                     /* -- write bottom line (up) -- */
  270.                     int y=RectBottom(rc)-GetClientTop(wnd);
  271.                     WriteTextLine(wnd, NULL,
  272.                         wnd->wtop+y, FALSE);
  273.                 }
  274.             }
  275.         }
  276.         /* ---- reset the scroll box ---- */
  277.         if (TestAttribute(wnd, VSCROLLBAR))    {
  278.             int vscrollbox = ComputeVScrollBox(wnd);
  279.             if (vscrollbox != wnd->VScrollBox)
  280.                 MoveScrollBox(wnd, vscrollbox);
  281.         }
  282.     }
  283.     return TRUE;
  284. }
  285.  
  286. /* ------------ HORIZSCROLL Message -------------- */
  287. static BOOL HorizScrollMsg(WINDOW wnd, PARAM p1)
  288. {
  289.     /* --- horizontal scroll one column --- */
  290.     if (p1)    {
  291.         /* --- scroll left --- */
  292.         if (wnd->wleft + ClientWidth(wnd)-1 >= wnd->textwidth)
  293.             return FALSE;
  294.         wnd->wleft++;
  295.     }
  296.     else    {
  297.         /* --- scroll right --- */
  298.         if (wnd->wleft == 0)
  299.             return FALSE;
  300.         --wnd->wleft;
  301.     }
  302.     SendMessage(wnd, PAINT, 0, 0);
  303.     return TRUE;
  304. }
  305.  
  306. /* ------------  SCROLLPAGE Message -------------- */
  307. static void ScrollPageMsg(WINDOW wnd, PARAM p1)
  308. {
  309.     /* --- vertical scroll one page --- */
  310.     if ((int) p1 == FALSE)    {
  311.         /* ---- page up ---- */
  312.         if (wnd->wtop)
  313.             wnd->wtop -= ClientHeight(wnd);
  314.     }
  315.     else     {
  316.         /* ---- page down ---- */
  317.         if (wnd->wtop+ClientHeight(wnd) < wnd->wlines) {
  318.             wnd->wtop += ClientHeight(wnd);
  319.             if (wnd->wtop>wnd->wlines-ClientHeight(wnd))
  320.                 wnd->wtop=wnd->wlines-ClientHeight(wnd);
  321.         }
  322.     }
  323.     if (wnd->wtop < 0)
  324.         wnd->wtop = 0;
  325.     SendMessage(wnd, PAINT, 0, 0);
  326. }
  327.  
  328. /* ------------ HORIZSCROLLPAGE Message -------------- */
  329. static void HorizScrollPageMsg(WINDOW wnd, PARAM p1)
  330. {
  331.     /* --- horizontal scroll one page --- */
  332.     if ((int) p1 == FALSE)
  333.         /* ---- page left ----- */
  334.         wnd->wleft -= ClientWidth(wnd);
  335.     else    {
  336.         /* ---- page right ----- */
  337.         wnd->wleft += ClientWidth(wnd);
  338.         if (wnd->wleft > wnd->textwidth-ClientWidth(wnd))
  339.             wnd->wleft = wnd->textwidth-ClientWidth(wnd);
  340.     }
  341.     if (wnd->wleft < 0)
  342.         wnd->wleft = 0;
  343.     SendMessage(wnd, PAINT, 0, 0);
  344. }
  345.  
  346. /* ------------ SCROLLDOC Message -------------- */
  347. static void ScrollDocMsg(WINDOW wnd, PARAM p1)
  348. {
  349.     /* --- scroll to beginning or end of document --- */
  350.     if ((int) p1)
  351.         wnd->wtop = wnd->wleft = 0;
  352.     else if (wnd->wtop+ClientHeight(wnd) < wnd->wlines){
  353.         wnd->wtop = wnd->wlines-ClientHeight(wnd);
  354.         wnd->wleft = 0;
  355.     }
  356.     SendMessage(wnd, PAINT, 0, 0);
  357. }
  358.  
  359. /* ------------ PAINT Message -------------- */
  360. static void PaintMsg(WINDOW wnd, PARAM p1, PARAM p2)
  361. {
  362.     /* ------ paint the client area ----- */
  363.     RECT rc, rcc;
  364.     int y;
  365.     char blankline[201];
  366.  
  367.     /* ----- build the rectangle to paint ----- */
  368.     if ((RECT *)p1 == NULL)
  369.         rc=RelativeWindowRect(wnd, WindowRect(wnd));
  370.     else
  371.         rc= *(RECT *)p1;
  372.     if (TestAttribute(wnd, HASBORDER) &&
  373.             RectRight(rc) >= WindowWidth(wnd)-1) {
  374.         if (RectLeft(rc) >= WindowWidth(wnd)-1)
  375.             return;
  376.         RectRight(rc) = WindowWidth(wnd)-2;
  377.     }
  378.     rcc = AdjustRectangle(wnd, rc);
  379.  
  380.     if (!p2 && wnd != inFocus)
  381.         ClipString++;
  382.  
  383.     /* ----- blank line for padding ----- */
  384.     memset(blankline, ' ', SCREENWIDTH);
  385.     blankline[RectRight(rcc)+1] = '\0';
  386.  
  387.     /* ------- each line within rectangle ------ */
  388.     for (y = RectTop(rc); y <= RectBottom(rc); y++){
  389.         int yy;
  390.         /* ---- test outside of Client area ---- */
  391.         if (TestAttribute(wnd,
  392.                     HASBORDER | HASTITLEBAR))    {
  393.             if (y < TopBorderAdj(wnd))
  394.                 continue;
  395.             if (y > WindowHeight(wnd)-2)
  396.                 continue;
  397.         }
  398.         yy = y-TopBorderAdj(wnd);
  399.         if (yy < wnd->wlines-wnd->wtop)
  400.             /* ---- paint a text line ---- */
  401.             WriteTextLine(wnd, &rc,
  402.                         yy+wnd->wtop, FALSE);
  403.         else    {
  404.             /* ---- paint a blank line ---- */
  405.             SetStandardColor(wnd);
  406.             writeline(wnd, blankline+RectLeft(rcc),
  407.                     RectLeft(rcc)+BorderAdj(wnd), y, FALSE);
  408.         }
  409.     }
  410.     /* ------- position the scroll box ------- */
  411.     if (TestAttribute(wnd, VSCROLLBAR|HSCROLLBAR)) {
  412.         int hscrollbox = ComputeHScrollBox(wnd);
  413.         int vscrollbox = ComputeVScrollBox(wnd);
  414.         if (hscrollbox != wnd->HScrollBox ||
  415.                 vscrollbox != wnd->VScrollBox)    {
  416.             wnd->HScrollBox = hscrollbox;
  417.             wnd->VScrollBox = vscrollbox;
  418.             SendMessage(wnd, BORDER, p1, 0);
  419.         }
  420.     }
  421.     if (!p2 && wnd != inFocus)
  422.         --ClipString;
  423. }
  424.  
  425. /* ------------ CLOSE_WINDOW Message -------------- */
  426. static void CloseWindowMsg(WINDOW wnd)
  427. {
  428.     SendMessage(wnd, CLEARTEXT, 0, 0);
  429.     if (wnd->TextPointers != NULL)    {
  430.         free(wnd->TextPointers);
  431.         wnd->TextPointers = NULL;
  432.     }
  433. }
  434.  
  435. /* ----------- TEXTBOX Message-processing Module ----------- */
  436. int TextBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  437. {
  438.     switch (msg)    {
  439.         case CREATE_WINDOW:
  440.             wnd->HScrollBox = wnd->VScrollBox = 1;
  441.             ClearTextPointers(wnd);
  442.             break;
  443.         case ADDTEXT:
  444.             return AddTextMsg(wnd, (char *) p1);
  445.         case DELETETEXT:
  446.             DeleteTextMsg(wnd, (int) p1);
  447.             return TRUE;
  448.         case INSERTTEXT:
  449.             InsertTextMsg(wnd, (char *) p1, (int) p2);
  450.             return TRUE;
  451.         case SETTEXT:
  452.             SetTextMsg(wnd, (char *) p1);
  453.             return TRUE;
  454.         case CLEARTEXT:
  455.             ClearTextMsg(wnd);
  456.             break;
  457.         case KEYBOARD:
  458.             if (WindowMoving || WindowSizing)
  459.                 break;
  460.             if (KeyboardMsg(wnd, p1))
  461.                 return TRUE;
  462.             break;
  463.         case LEFT_BUTTON:
  464.             if (WindowSizing || WindowMoving)
  465.                 return FALSE;
  466.             if (LeftButtonMsg(wnd, p1, p2))
  467.                 return TRUE;
  468.             break;
  469.         case MOUSE_MOVED:
  470.             if (MouseMovedMsg(wnd, p1, p2))
  471.                 return TRUE;
  472.             break;
  473.         case BUTTON_RELEASED:
  474.             ButtonReleasedMsg(wnd);
  475.             break;
  476.         case SCROLL:
  477.             return ScrollMsg(wnd, p1);
  478.         case HORIZSCROLL:
  479.             return HorizScrollMsg(wnd, p1);
  480.         case SCROLLPAGE:
  481.             ScrollPageMsg(wnd, p1);
  482.             return TRUE;
  483.         case HORIZPAGE:
  484.             HorizScrollPageMsg(wnd, p1);
  485.             return TRUE;
  486.         case SCROLLDOC:
  487.             ScrollDocMsg(wnd, p1);
  488.             return TRUE;
  489.         case PAINT:
  490.             if (isVisible(wnd))    {
  491.                 PaintMsg(wnd, p1, p2);
  492.                 return FALSE;
  493.             }
  494.             break;
  495.         case CLOSE_WINDOW:
  496.             CloseWindowMsg(wnd);
  497.             break;
  498.         default:
  499.             break;
  500.     }
  501.     return BaseWndProc(TEXTBOX, wnd, msg, p1, p2);
  502. }
  503.  
  504. /* ------ compute the vertical scroll box position from
  505.                    the text pointers --------- */
  506. static int ComputeVScrollBox(WINDOW wnd)
  507. {
  508.     int pagelen = wnd->wlines - ClientHeight(wnd);
  509.     int barlen = ClientHeight(wnd)-2;
  510.     int lines_tick;
  511.     int vscrollbox;
  512.  
  513.     if (pagelen < 1 || barlen < 1)
  514.         vscrollbox = 1;
  515.     else    {
  516.         if (pagelen > barlen)
  517.             lines_tick = pagelen / barlen;
  518.         else
  519.             lines_tick = barlen / pagelen;
  520.         vscrollbox = 1 + (wnd->wtop / lines_tick);
  521.         if (vscrollbox > ClientHeight(wnd)-2 ||
  522.                 wnd->wtop + ClientHeight(wnd) >= wnd->wlines)
  523.             vscrollbox = ClientHeight(wnd)-2;
  524.     }
  525.     return vscrollbox;
  526. }
  527.  
  528. /* ---- compute top text line from scroll box position ---- */
  529. static void ComputeWindowTop(WINDOW wnd)
  530. {
  531.     int pagelen = wnd->wlines - ClientHeight(wnd);
  532.     if (wnd->VScrollBox == 0)
  533.         wnd->wtop = 0;
  534.     else if (wnd->VScrollBox == ClientHeight(wnd)-2)
  535.         wnd->wtop = pagelen;
  536.     else    {
  537.         int barlen = ClientHeight(wnd)-2;
  538.         int lines_tick;
  539.  
  540.         if (pagelen > barlen)
  541.             lines_tick = pagelen / barlen;
  542.         else
  543.             lines_tick = barlen / pagelen;
  544.         wnd->wtop = (wnd->VScrollBox-1) * lines_tick;
  545.         if (wnd->wtop + ClientHeight(wnd) > wnd->wlines)
  546.             wnd->wtop = pagelen;
  547.     }
  548.     if (wnd->wtop < 0)
  549.         wnd->wtop = 0;
  550. }
  551.  
  552. /* ------ compute the horizontal scroll box position from
  553.                    the text pointers --------- */
  554. static int ComputeHScrollBox(WINDOW wnd)
  555. {
  556.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  557.     int barlen = ClientWidth(wnd)-2;
  558.     int chars_tick;
  559.     int hscrollbox;
  560.  
  561.     if (pagewidth < 1 || barlen < 1)
  562.         hscrollbox = 1;
  563.     else     {
  564.         if (pagewidth > barlen)
  565.             chars_tick = pagewidth / barlen;
  566.         else
  567.             chars_tick = barlen / pagewidth;
  568.         hscrollbox = 1 + (wnd->wleft / chars_tick);
  569.         if (hscrollbox > ClientWidth(wnd)-2 ||
  570.                 wnd->wleft + ClientWidth(wnd) >= wnd->textwidth)
  571.             hscrollbox = ClientWidth(wnd)-2;
  572.     }
  573.     return hscrollbox;
  574. }
  575.  
  576. /* ---- compute left column from scroll box position ---- */
  577. static void ComputeWindowLeft(WINDOW wnd)
  578. {
  579.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  580.  
  581.     if (wnd->HScrollBox == 0)
  582.         wnd->wleft = 0;
  583.     else if (wnd->HScrollBox == ClientWidth(wnd)-2)
  584.         wnd->wleft = pagewidth;
  585.     else    {
  586.         int barlen = ClientWidth(wnd)-2;
  587.         int chars_tick;
  588.  
  589.         if (pagewidth > barlen)
  590.             chars_tick = pagewidth / barlen;
  591.         else
  592.             chars_tick = barlen / pagewidth;
  593.         wnd->wleft = (wnd->HScrollBox-1) * chars_tick;
  594.         if (wnd->wleft + ClientWidth(wnd) > wnd->textwidth)
  595.             wnd->wleft = pagewidth;
  596.     }
  597.     if (wnd->wleft < 0)
  598.         wnd->wleft = 0;
  599. }
  600.  
  601. /* ----- get the text to a specified line ----- */
  602. static char *GetTextLine(WINDOW wnd, int selection)
  603. {
  604.     char *line;
  605.     int len = 0;
  606.     char *cp, *cp1;
  607.     cp = cp1 = TextLine(wnd, selection);
  608.     while (*cp && *cp != '\n')    {
  609.         len++;
  610.         cp++;
  611.     }
  612.     line = DFmalloc(len+6);
  613.     memmove(line, cp1, len);
  614.     line[len] = '\0';
  615.     return line;
  616. }
  617.  
  618. /* ------- write a line of text to a textbox window ------- */
  619. void WriteTextLine(WINDOW wnd, RECT *rcc, int y, BOOL reverse)
  620. {
  621.     int len = 0;
  622.     int dif = 0;
  623.     unsigned char line[200];
  624.     RECT rc;
  625.     unsigned char *lp, *svlp;
  626.     int lnlen;
  627.     int i;
  628.     BOOL trunc = FALSE;
  629.  
  630.     /* ------ make sure y is inside the window ----- */
  631.     if (y < wnd->wtop || y >= wnd->wtop+ClientHeight(wnd))
  632.         return;
  633.  
  634.     /* ---- build the retangle within which can write ---- */
  635.     if (rcc == NULL)    {
  636.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  637.         if (TestAttribute(wnd, HASBORDER) &&
  638.                 RectRight(rc) >= WindowWidth(wnd)-1)
  639.             RectRight(rc) = WindowWidth(wnd)-2;
  640.     }
  641.     else
  642.         rc = *rcc;
  643.  
  644.     /* ----- make sure rectangle is within window ------ */
  645.     if (RectLeft(rc) >= WindowWidth(wnd)-1)
  646.         return;
  647.     if (RectRight(rc) == 0)
  648.         return;
  649.     rc = AdjustRectangle(wnd, rc);
  650.     if (y-wnd->wtop<RectTop(rc) || y-wnd->wtop>RectBottom(rc))
  651.         return;
  652.  
  653.     /* --- get the text and length of the text line --- */
  654.     lp = svlp = GetTextLine(wnd, y);
  655.     if (svlp == NULL)
  656.         return;
  657.     lnlen = LineLength(lp);
  658.  
  659.     /* -------- insert block color change controls ------- */
  660.     if (TextBlockMarked(wnd))    {
  661.         int bbl = wnd->BlkBegLine;
  662.         int bel = wnd->BlkEndLine;
  663.         int bbc = wnd->BlkBegCol;
  664.         int bec = wnd->BlkEndCol;
  665.         int by = y;
  666.  
  667.         /* ----- put lowest marker first ----- */
  668.         if (bbl > bel)    {
  669.             swap(bbl, bel);
  670.             swap(bbc, bec);
  671.         }
  672.         if (bbl == bel && bbc > bec)
  673.             swap(bbc, bec);
  674.  
  675.         if (by >= bbl && by <= bel)    {
  676.             /* ------ the block includes this line ----- */
  677.             int blkbeg = 0;
  678.             int blkend = lnlen;
  679.             if (!(by > bbl && by < bel))    {
  680.                 /* --- the entire line is not in the block -- */
  681.                 if (by == bbl)
  682.                     /* ---- the block begins on this line --- */
  683.                     blkbeg = bbc;
  684.                 if (by == bel)
  685.                     /* ---- the block ends on this line ---- */
  686.                     blkend = bec;
  687.             }
  688.             /* ----- insert the reset color token ----- */
  689.             memmove(lp+blkend+1,lp+blkend,strlen(lp+blkend)+1);
  690.             lp[blkend] = RESETCOLOR;
  691.             /* ----- insert the change color token ----- */
  692.             memmove(lp+blkbeg+3,lp+blkbeg,strlen(lp+blkbeg)+1);
  693.             lp[blkbeg] = CHANGECOLOR;
  694.             /* ----- insert the color tokens ----- */
  695.             SetReverseColor(wnd);
  696.             lp[blkbeg+1] = foreground | 0x80;
  697.             lp[blkbeg+2] = background | 0x80;
  698.             lnlen += 4;
  699.         }
  700.     }
  701.     /* - make sure left margin doesn't overlap color change - */
  702.     for (i = 0; i < wnd->wleft+3; i++)    {
  703.         if (*(lp+i) == '\0')
  704.             break;
  705.         if (*(unsigned char *)(lp + i) == RESETCOLOR)
  706.             break;
  707.     }
  708.     if (*(lp+i) && i < wnd->wleft+3)    {
  709.         if (wnd->wleft+4 > lnlen)
  710.             trunc = TRUE;
  711.         else 
  712.             lp += 4;
  713.     }
  714.     else     {
  715.         /* --- it does, shift the color change over --- */
  716.         for (i = 0; i < wnd->wleft; i++)    {
  717.             if (*(lp+i) == '\0')
  718.                 break;
  719.             if (*(unsigned char *)(lp + i) == CHANGECOLOR)    {
  720.                 *(lp+wnd->wleft+2) = *(lp+i+2);
  721.                 *(lp+wnd->wleft+1) = *(lp+i+1);
  722.                 *(lp+wnd->wleft) = *(lp+i);
  723.                 break;
  724.             }
  725.         }
  726.     }
  727.     /* ------ build the line to display -------- */
  728.     if (!trunc)    {
  729.         if (lnlen < wnd->wleft)
  730.             lnlen = 0;
  731.         else
  732.             lp += wnd->wleft;
  733.         if (lnlen > RectLeft(rc))    {
  734.             /* ---- the line exceeds the rectangle ---- */
  735.             int ct = RectLeft(rc);
  736.             char *initlp = lp;
  737.             /* --- point to end of clipped line --- */
  738.             while (ct)    {
  739.                 if (*(unsigned char *)lp == CHANGECOLOR)
  740.                     lp += 3;
  741.                 else if (*(unsigned char *)lp == RESETCOLOR)
  742.                     lp++;
  743.                 else
  744.                     lp++, --ct;
  745.             }
  746.             if (RectLeft(rc))    {
  747.                 char *lpp = lp;
  748.                 while (*lpp)    {
  749.                     if (*(unsigned char*)lpp==CHANGECOLOR)
  750.                         break;
  751.                     if (*(unsigned char*)lpp==RESETCOLOR) {
  752.                         lpp = lp;
  753.                         while (lpp >= initlp)    {
  754.                             if (*(unsigned char *)lpp ==
  755.                                             CHANGECOLOR) {
  756.                                 lp -= 3;
  757.                                 memmove(lp,lpp,3);
  758.                                 break;
  759.                             }
  760.                             --lpp;
  761.                         }
  762.                         break;
  763.                     }
  764.                     lpp++;
  765.                 }
  766.             }
  767.             lnlen = LineLength(lp);
  768.             len = min(lnlen, RectWidth(rc));
  769.             dif = strlen(lp) - lnlen;
  770.             len += dif;
  771.             if (len > 0)
  772.                 strncpy(line, lp, len);
  773.         }
  774.     }
  775.     /* -------- pad the line --------- */
  776.     while (len < RectWidth(rc)+dif)
  777.         line[len++] = ' ';
  778.     line[len] = '\0';
  779.     dif = 0;
  780.     /* ------ establish the line's main color ----- */
  781.     if (reverse)    {
  782.         char *cp = line;
  783.         SetReverseColor(wnd);
  784.         while ((cp = strchr(cp, CHANGECOLOR)) != NULL)    {
  785.             cp += 2;
  786.             *cp++ = background | 0x80;
  787.         }
  788.         if (*(unsigned char *)line == CHANGECOLOR)
  789.             dif = 3;
  790.     }
  791.     else
  792.         SetStandardColor(wnd);
  793.     /* ------- display the line -------- */
  794.     writeline(wnd, line+dif,
  795.                 RectLeft(rc)+BorderAdj(wnd),
  796.                     y-wnd->wtop+TopBorderAdj(wnd), FALSE);
  797.     free(svlp);
  798. }
  799.  
  800. void MarkTextBlock(WINDOW wnd, int BegLine, int BegCol,
  801.                                int EndLine, int EndCol)
  802. {
  803.     wnd->BlkBegLine = BegLine;
  804.     wnd->BlkEndLine = EndLine;
  805.     wnd->BlkBegCol = BegCol;
  806.     wnd->BlkEndCol = EndCol;
  807. }
  808.  
  809. /* ----- clear and initialize text line pointer array ----- */
  810. void ClearTextPointers(WINDOW wnd)
  811. {
  812.     wnd->TextPointers = DFrealloc(wnd->TextPointers, sizeof(int));
  813.     *(wnd->TextPointers) = 0;
  814. }
  815.  
  816. #define INITLINES 100
  817.  
  818. /* ---- build array of pointers to text lines ---- */
  819. void BuildTextPointers(WINDOW wnd)
  820. {
  821.     char *cp = wnd->text, *cp1;
  822.     int incrs = INITLINES;
  823.     unsigned int off;
  824.     wnd->textwidth = wnd->wlines = 0;
  825.     while (*cp)    {
  826.         if (incrs == INITLINES)    {
  827.             incrs = 0;
  828.             wnd->TextPointers = DFrealloc(wnd->TextPointers,
  829.                     (wnd->wlines + INITLINES) * sizeof(int));
  830.         }
  831.         off = (unsigned int) (cp - wnd->text);
  832.         *((wnd->TextPointers) + wnd->wlines) = off;
  833.         wnd->wlines++;
  834.         incrs++;
  835.         cp1 = cp;
  836.         while (*cp && *cp != '\n')
  837.             cp++;
  838.         wnd->textwidth = max(wnd->textwidth,
  839.                         (unsigned int) (cp - cp1));
  840.         if (*cp)
  841.             cp++;
  842.     }
  843. }
  844.  
  845. static void MoveScrollBox(WINDOW wnd, int vscrollbox)
  846. {
  847.     foreground = FrameForeground(wnd);
  848.     background = FrameBackground(wnd);
  849.     wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  850.             wnd->VScrollBox+1);
  851.     wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  852.             vscrollbox+1);
  853.     wnd->VScrollBox = vscrollbox;
  854. }
  855.  
  856. int TextLineNumber(WINDOW wnd, char *lp)
  857. {
  858.     int lineno;
  859.     char *cp;
  860.     for (lineno = 0; lineno < wnd->wlines; lineno++)    {
  861.         cp = wnd->text + *((wnd->TextPointers) + lineno);
  862.         if (cp == lp)
  863.             return lineno;
  864.         if (cp > lp)
  865.             break;
  866.     }
  867.     return lineno-1;
  868. }
  869.  
  870.  
  871. 
  872.